# -*- coding: utf-8 -*-
"""
    moe.models
    ~~~~~~~~~~

    Base models.

    :copyright: 2009 by tipfy.org.
    :license: BSD, see LICENSE.txt for more details.
"""
import datetime
import logging

from google.appengine.api import datastore_errors
from google.appengine.ext import db

from werkzeug import cached_property

from tipfy.appengine.auth.model import User as BaseUser
from tipfy.appengine.db import KeyProperty, ModelMixin, get_entity_dict


class DateMixin(ModelMixin):
    # Creation date.
    created = db.DateTimeProperty(auto_now_add=True)
    # Modification date.
    updated = db.DateTimeProperty(auto_now=True)


class User(BaseUser):
    pass


class RevisionModel(db.Model):
    """Base model for entities that keep a revision history. Example::

        class WikiPage(RevisionModel):
            body = db.TextProperty()
            note = db.StringProperty()

        # Add a new page.
        page = WikiPage(key_name='first-page', body='just testing',
            note='initial version')
        page.put()

        # When the entity is saved for the second time, the current version
        # is stored in the version history.
        page = WikiPage(key_name='first-page', body='testing again',
            note='edited version')
        page.put()

        # It can also be used without key name:
        page = WikiPage.get_by_id(some_id)
        if page:
            page.body = 'testing again'
            page.note = 'edited version'
            page.put()

    To fetch all latest revisions, filter using is_root=True::

        all_pages = WikiPage.all().filter('is_root', True).fetch(10)

    To fetch all revisions of a given record, filter using the latest
    revision as ancestor::

        page = WikiPage.get_by_key_name('first-page')
        if page:
            revisions = WikiPage.all().ancestor(page).fetch(10)
    """
    # Creation date.
    created = db.DateTimeProperty()
    # Modification date.
    updated = db.DateTimeProperty()
    # True if this entity is the latest revision (has no ancestors).
    is_root = db.BooleanProperty(default=True)

    def put_transaction(self, entities=None):
        """Helper for extended classes to run their own transactions
        involving a versioned entity.
        """
        now = datetime.datetime.now()
        self.created = now
        self.updated = now
        self.is_root = True

        if entities is None:
            entities = []
        elif not isinstance(entities, list):
            entities = [entities]

        entities.append(self)

        if self.has_key():
            current_version = db.get(self.key())
        else:
            current_version = None

        if current_version is not None:
            # Save old data in the revision history with current entity
            # as parent.
            old_data = get_entity_dict(current_version)
            old_data['is_root'] = False
            old_version = self.__class__(parent=self, **old_data)
            entities.append(old_version)

        return db.put(entities)


class ArticleRevisionModel(RevisionModel):
    # Editor of this version: a reference identifier to an authenticated user.
    editor_key = KeyProperty()
    # IP address of the editor.
    editor_ip = db.StringProperty()
    # Page title.
    title = db.StringProperty()
    # Body formatted message.
    body = db.TextProperty()
    # Body raw message, as posted by the user. Only displayed when editing.
    body_raw = db.TextProperty()
    # Format name: defines a markup processor such as Creole or Markdown.
    format = db.StringProperty(required=True, default='creole')
    # Status code: varies depending on the implementation class. Example:
    # 0: awaiting moderation, 1: active, 2: deleted etc.
    status = db.IntegerProperty(default=1)
    # Store tags mostly to keep track of tag changes, not to query.
    tags = db.StringListProperty()
    # Change notes, set when the entity is updated.
    notes = db.StringProperty()

    @cached_property
    def editor(self):
        # XXX use global entity cache.
        if self.editor_key:
            return User.get(self.editor_key)


#class Area(db.Model):
#    name = db.StringProperty()
#    owner = db.StringProperty()
